iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
Software Development

一個好的系統之好維護基本篇 ( 馬克版 )系列 第 28

Day-28: 高品質的特性與指標探索 - 維護性

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20241012/20089358eyHv8b1TaT.png

事實上我們有當過工程師的人都知道,維護性這個東西的指標是真的難定,但是我們每個人都知道要有維護性。

如果上層是可以理解這一塊的,那事實上還好,但是如果上層是那種要求一定要給個指標,那真的會很幹,有時後我會很想和他們要求,要做個產品可以給我們評估要不要做的指標嗎 ? 但事實上這個是我最不太想走到的一步,因為小公司還需要每個東西都要求,那只會變慢 + 增加不信任,理想上工程、產品、工程應該是要站在一條線的。

然後接下來這裡是我儘可能可以尋找到的指標,可以拿來參考一下。

在開始之前,我想先理一下高品質的系統有那些特性呢 ?


一個高品質的系統有那些特性呢 ?

雖然在第一篇文章時,我們有提到 ISO/IEC 25010 有一下定義,但我這裡還想參考一下其它書籍的定義,最後在來收斂成一個。

Day-01: 之開篇與軟體工程維護性

1. ISO/IEC 25010

https://ithelp.ithome.com.tw/upload/images/20240915/20089358dbqjlF0vtq.png
https://iso25000.com/index.php/en/iso-25000-standards/iso-25010

其中它有分為以下幾個大項:

  • Functional Suitability : 這一塊主要就是功能是否符合需求,其中子特性為功能完整性、功能整確性、功能適當性。
  • Performance Efficiency : 就高效能,可參考我之前的 30天之從 0 至 1 盡可能的建立一個好的系統 (性能基礎篇)
  • Compatibility: 這個我有點不確定,但就我的理解應該就是不同的系統、產品能不能在不互相干擾的情況下進行合作,獨立運行。
  • Interaction Capability: 這個我覺得比較接近 UI/UX 的部份,有興趣的可以去看它們的子特徵。
  • Reliability: 就可靠性,這個可以指軟體與系統兩方面都是,以軟體面來說 transaction 就是個達成可靠性的方法,而系統面的 failover 也是達成系統面的可靠性。
  • Security: 就資安。然後以前有一次鐵人賽是寫這方面的,但事實上有點文不對題,不過反正只是自我挑戰組的,其中最後一篇我覺得就可以當個地圖來看看。30-30 : 馬克的資安初階小地圖
  • Maintainability: 就是我們這次鐵人賽的主題。
  • Flexibility: 這個比較接近系統面的那一塊,如果以我的角度來看比較接近 docker、k8s 那一塊的東西。
  • Safety: 這個雖然他文中提到避免危及人類生命、健康、財產啥的…… 但他的子特性就比較像是在說錯誤監控的東西。

然後我們這 30 天都在探討好維護,所以我這裡就先將維護性抓出來說 :

  • Modularity : 這個就是在說它可以獨立運行的元件,然後它的特性就是我們常說的高內聚低耦合,但後我們有大部份的文章都在說這塊。
  • Reusability : 就是 DRY,這題我覺得要在上面模組化的特性下,才能運行,不然如果每有先分,然後每個地方看到可以用的就 DRY,你整個系統就是改一個炸全身的概念。
  • Analysability : 它這個比較程式碼好理解、logging、並且也有提到可以分析整個軟體工程的狀況。
  • Modifiability : 就是解耦,不要改了一個炸一個。
  • Testability : 這個主要依賴有沒有獨立,並且測試碼好不好測試,我們在 DI 與 SRP 時應該都有提到。

2. 設計重構:25個管理技術債的技巧消除軟體設計臭味

然後接下來我們來參考其它書籍中提到的高品質的定義,下面這個為 《 設計重構:25個管理技術債的技巧消除軟體設計臭味 》這本書中裡面提到的高品質的系統有以下條件如下:

  • 可理解性
  • 可修改性
  • 可擴展性
  • 可重用性
  • 可測試性
  • 可靠性

事實上都有 cover 到上面提的那幾個,好像也沒有那個比較特別是上面那個沒有的。過這本書是專注在重構這塊,所以他沒有列其它非維護性的品質指標。

然後這本書我超推。

3. Clean Architecture 實作篇第二版

在《 Clean Architecture 實作篇第二版 》書中提到,作者有和 ChatGPT 問的答案是 :

  • 擴展性 ( Scalability )
  • 靈活性 ( Flexibility )
  • 可維護性 ( Maintainability )
  • 安全性 ( Security )
  • 可靠性 ( Reliability )
  • 模組化 ( Modularity )
  • 效能 ( Performance )
  • 可互通性 ( interoperability )
  • 可測試性 ( Testability )
  • 成本效益 ( Cost-effectiveness )

然後作者認為將可維護性與其它的品質需求混為一談是不正確的,因為他認為『 上列的清單,所有都和可維護性有關聯。

作者認為,可維護性比功能性更為重要,所以不應該為了提供價值,而以可維護性作為代價,因為最後付出代價的公司。

下面這張圖,我自已認為,就是最好形容這件事情的,我們家事實上就是走上紅線那一塊,一個 code base 有四種軟體架構……

https://ithelp.ithome.com.tw/upload/images/20241012/200893588niokcdt4d.png

前期新創時如果要快速的產生 MVP 之類的,用最快的速度交付,並且犧牲一些可維護性,我自已覺得還算合理,只是比較大的問題在於 :

之後有沒有還債呢 ? 還有還債的方法是『 工程師自已覺得好維護的手法 ? 還是軟體工程的經驗手法呢 ? 』

我在這麼多間產品、平台類的公司待過,我現在很能理解一句話就是 :

一間以軟體產品為主的公司要走的長遠,除了點子外,軟體工程維護性絕對是最重要的。

4. FURPS

這個是由五個單字合成的一成的品質特性,這個好像是由 HP 公司提出,然後它好像還有一些衍伸例如 FURPS+、FURPS 等,這裡就先說說最簡單的。

  • Function
  • Usability
  • Reliability
  • Performance
  • Supportability

這五個除了 Usability 與 Supportability 可能比較需要說一下外其它應該都在上面有出現過了。

Usability 在 wiki 是寫說美學、一致性、說明文件,然後我自已的理解就比較算是可理解性那一塊。然後 Supportability 就有點是大雜燴,我直接貼 wiki 內容參考看看 :

易測性、延伸性、適應性、可維護性、相容性、 可組態性(Configurability)、可服務性(Serviceability)、可安裝性(Installability)、在地化能力(Localizability)、可攜性( Portability)。


維護性特性總結

  • ISO/IEC 25010
  • 設計重構:25個管理技術債的技巧消除軟體設計臭味
  • Clean Architecture 實作篇第二版
  • FURPS

整體來說我事實上覺得大同小異,幾乎已經沒差多少了,所以事實上在軟體工程界對高品質的系統概念上是都差不多,然後這裡就整理合成一個版本的。

  • 高內聚低耦合的元件: 這個很接近我們在 Bounded Context 說的概念,它能越獨立越好。
  • 可理解性: 就是我們的程式碼可以給人讀懂,並且複雜度不高,並且認知負荷是可以接受的。
  • 可修改與擴展性: 很接近 OCP 看原則,反正就是要好修改與好擴展。
  • 可重用性: 就是 DRY。
  • 可測試性: 就是要可以測試。
  • 可靠性: 就是這個軟體是穩的,不要很多問題。

然後事實上這幾個特性他們事實上都互相有一定關係,但要合在一起又覺得好像少了什麼,所以我覺得就先這樣。

指標 1. SPACE 中的 S ( 開發者生產力指標 )

Clean Architecture 實作篇第二版中有提到一個概念 :

Developer Joy 或是 Developer Enablement

開發者樂趣與開發者生產力事實上非常的相關,各位朋朋想想看,你是不是在開發全新的東西時,心情會比在 legacy 一堆的專案開發東西還要開心,而且速度與品質也更好。

所以書中提出的一個指標就是來衡量這個東西,那就是 :

SPACE 框架中的 S

這個指標是在 2021 年時,由 Nicole Forsgren 在『 The SPACE of Developer Productivity 』中提出的,分別為 :

  • S ( Satisfaction and well-being ) : 滿意度和幸福感
  • P ( Performance ) : 表現
  • A ( Activity ) : 活動
  • C ( Communication and collaboration ) : 溝通與協作
  • E ( efficiency and flow )

所以書中認如果你的 S 是好的,開發時是有樂趣的,那事實上也就代表你的系統有一定的維護性

然後這個指標要如何衡量呢 ?

問卷、1 on 1

備註 :
提外話一下,這個也是我當上主管一段時間,面臨到的問題,那就是如何衡量開發團隊生產力指標過程中,發現到的其中一個,另外幾個是 Dora,接下來還有擴展的 DevEx,有興趣的新手主管朋朋們可以用這些 keyword 來查查 ~


指標 2. SIG 指標

這個指標是在看這本《打造可維護軟體:編寫可維護程式碼的10項法則 (C#版)》看到的,給了我一條路啊 ~

然後這份文件是 SIG/TÜViT 《可信產品可維護性評估標準》(SIG 2024)。

SIG 《可信產品可維護性評估標準》(SIG 2024)

雖然我自已不太喜歡什麼認證,但它事實上裡面有提到不少我覺得還不錯的指標:

1. Volume: 程式碼數量

程式碼數量事實上我覺得他的確也可以當一種維護性指標,越多行數的程式碼的確會越難維護,同時也代表需要越多人維護,然後下圖是文中的行業標準的程式碼行數平均值,不過就當參考吧 ~ 然後它的意思是如果要拿他們的 4 星,就不要超過 30 萬行左右。

然後我自已的想法是,行數多事實上也代表他做很多事,或是那些 code 是沒用的,但是不管如何,我們每一次寫程式碼時總是要對看過去的東西,再來實作,所以舊東西越多,我們維護難度越會增加,所以記得要多砍 code 啊。

https://ithelp.ithome.com.tw/upload/images/20241012/20089358CL1bgniq13.png
圖片來源: 《可信產品可維護性評估標準》(SIG 2024)

2. Duplication: 就是重複的程式碼

這個應該沒毛病,應該是不太需要多說

3. Unit Size + Complexity + Interfacing

先說一下這篇文章的 Unit 的定義如下:

The notion of unit is defined as the smallest named piece of executable code. This may correspond to different terms in each programming language. For example, for object-oriented languages methods are regarded as units whereas for procedural languages

事實上就是 method

然後首先我們先來說 Size。這個咱們應該都知道,一個方法不太適合太長,因為太長有幾種問題:

  • 難理解
  • 可能沒有單一職責
  • 難測試
  • 難重用

然後文中 4 星的要求如下,但一樣就當個參考就好。

  • 超過 15 行代碼的單元行數佔總代碼行數的比例不得超過 46.0%。
  • 超過 30 行代碼的單元行數佔總代碼行數的比例不得超過 21.9%。
  • 超過 60 行代碼的單元行數佔總代碼行數的比例不得超過 7.7%。

https://ithelp.ithome.com.tw/upload/images/20241012/20089358NZMtZqBFSp.png
圖片來源: 《可信產品可維護性評估標準》(SIG 2024)

然後接下來是 Completixty,然後它的複雜度計算是用一個叫 McCabe Cyclomatic Complexity 來計算,詳細的內容可以看下面連結,然後簡單的說就是一個方法中的路徑數,如下圖 :

Cyclomatic complexity-Thomas J. McCabe, Sr.

https://ithelp.ithome.com.tw/upload/images/20241012/20089358O00JKluvEe.png
圖片來源: 《可信產品可維護性評估標準》(SIG 2024)

最後一個是 Interfacing,就是通常如果一個方法有很多大型的 interface 或是很多參數時,那通常就代表它可能承擔多個職責,那他會變的得難修改。但我自已覺得這個地方應該要排除掉 Create 類的方法。

然後文中的 4 星要求如下:

  • 擁有 3 個或更多參數 的單元行數不得超過總代碼行數的 14.4%。
  • 擁有 5 個或更多參數 的單元行數不得超過總代碼行數的 2.9%。
  • 擁有 7 個或更多參數 的單元行數不得超過總代碼行數的 0.8%。

https://ithelp.ithome.com.tw/upload/images/20241012/200893585C5ojYV6AC.png
圖片來源: 《可信產品可維護性評估標準》(SIG 2024)

4. Module Coupling

Day-02: 設計原則 SOLID - SRP
Day-10: 實務時 Code Review 看 Class 地方 1 (基本)
Day-17: DI 的設計模式與臭臭的味道

這個東西就是我們在談 SRP 時,所提到的元件依賴變動,在 DI 的壞味道也有提到,反正很多地方都有提到,然後這個就是它的指標,然後要如何看它的依賴數量呢 ? 最簡單的方法就是 :

看你的 Import ( 以 ts 為例 ) + 看你的 Contruct Inject 的數量

例如下面範例一看就知道他依賴很多吧 ?

class OrderService {
  constructor(
    private paymentService: PaymentService,
    private notificationService: NotificationService,
    private inventoryService: InventoryService,
    private shippingService: ShippingService,
    private discountService: DiscountService,
    private taxService: TaxService,
    private customerService: CustomerService,
    private loggingService: LoggingService,
  ) {}

  processOrder(orderId: string, productId: string) {
    // 使用所有注入的服務來處理訂單
    this.inventoryService; // 檢查庫存
    this.paymentService;   // 處理付款
    this.shippingService;  // 處理運輸
    this.discountService;  // 計算折扣
    this.taxService;       // 計算稅額
    this.customerService;  // 確認客戶資料
    this.notificationService; // 發送通知
    this.loggingService;   // 記錄操作
  }
}

https://ithelp.ithome.com.tw/upload/images/20241012/20089358eE1VBIrVTJ.png

但這個數量也當參考就好,實務上我自已是會用整體的平均來看,例如你們平均大概每個才注入 5 ~ 6 個,但有一個 class 有 15 個,那他就可以拿來排入重構。

  • 輸入依賴數量超過 10 的模組行數佔總代碼行數的比例不得超過 9.8%。
  • 輸入依賴數量超過 20 的模組行數佔總代碼行數的比例不得超過 5.3%。
  • 輸入依賴數量超過 50 的模組行數佔總代碼行數的比例不得超過 1.6%。

5. Component Indepence

這個我覺得可以用 Bounded Context 來當單元比較好說,然後它的概念就是 :

讓 BC 更獨立,也就是說減少 Public Module,然後增加 Hidden Module

如果是有使用 Nestjs 就很容易可以看出它一個 Module export 的出量,認真的話應該是有辦法計算出所有 module 整個狀況。

https://ithelp.ithome.com.tw/upload/images/20241012/20089358A6nJ7keiN4.png
圖片來源: 《可信產品可維護性評估標準》(SIG 2024)

它這裡的 4 星期認證還真有點硬,為了達到 4 星級認證,隱藏模組中的代碼佔總代碼的比例不得低於 93.2%。這意味著超過 93.2% 的代碼應該位於沒有來自其他元件依賴的模組中,從而確保高程度的元件獨立性。

6. Component Entanglement

這個就是在說元件之間的相互依賴程度和它們之間的依賴複雜度。

它有兩個指標來計算 :

  • 溝通密度 Communication Density ( 依賴程度 )
  • 溝通違規程度 Communication Violation Degree) (依賴複雜度 )

其中違規它有三種違規 :

  • 循環依賴
  • 間接循環依賴
  • 傳遞依賴

其中前 2 個應該很容易懂,最後一個就是這個元件需要傳入多少元件,才能完成這個工作的意思。


指標 3. 我自已的補充

1. Bug 與錯誤數量

這裡我分為以下幾個:

  • 用戶回報的 Bug
  • QA Regression Bug
  • Flaky Test 數量
  • 未預期的系統錯誤量。

這些我自已都會拿來當衡量品質的指標。

2. Dev-Support 數量

Dev-Support 是我們家個奇怪制度,但也不能說奇怪,它整個功用就是 :

Bug 回報 + 請求工程完成一些東西

bug 那個沒啥話說,但另一個就是有點奇怪,在新創期,很多東西沒有 UI ,然後營運請求後端工程師來協助手動處理完成一些事情我覺得算合理,然後久了久就變成一項功能,然後這個功能是沒有 PRD + 讓 QA 驗證,也沒有寫那些 Spec 是可以處理這種情況的東西,最後就是變成跳過流程,然後由後端判斷看看可不可以處理。

然後如果真的要我說這個指標的代表了以下的意思 :

如果數量高,那事實上就代表我們產品與營運的斷層是很高的,就是我們產品完全不符合營運的需求,而且跳過了很多工程品質流程

所以這種情況,我就覺得如果這指標很高,那就算是我們維護性的減分項囉 ~

3. Code Coverage

這個雖然我不太會注重,但也不代表不需要,因為至少可以知道我的系統有幾 % 的程式有被測試覆蓋到,基本上就抓個 80% 我覺得就可以接受了,我自已是比較在意 spec 測試有沒有符合需求,如果不符合就算有 coverage 到做出來的東西還是沒用,但我現在也不知道如何做比較好,至少 code coverage 還算有點兒小幫忙。


小結

在軟體開發過程中維護性這個東西每個工程師都知到重要性,但實際上要其定義明確的指票是非常困難的,而且也因為很困難,所以導致我們每一次要求重構時都很常被營運、或上面說提出指標而被打槍。

然後這篇文章中我先探討了不同理論與書籍來討論高品質的指標,接下來就先專注在好維護的特點如下,就是上面的各本書的特性總結 :

  • 高內聚低耦合的元件: 這個很接近我們在 Bounded Context 說的概念,它能越獨立越好。
  • 可理解性: 就是我們的程式碼可以給人讀懂,並且複雜度不高,並且認知負荷是可以接受的。
  • 可修改與擴展性: 很接近 OCP 看原則,反正就是要好修改與好擴展。
  • 可重用性: 就是 DRY。
  • 可測試性: 就是要可以測試。
  • 可靠性: 就是這個軟體是穩的,不要很多問題。

然後接下來套用到下面的指標。

  • 高內聚低耦合的元件: SIG-ComponentIndepence、SIG-ComponentEntanglement
  • 可理解性: SPACE-S、SIG-Volum、SIG-Unit-Size、 SIG-UnitComplexity、SIG-ComponentIndepence、SIG-ComponentEntanglement
  • 可修改與擴展性: SPACE-S、SIG-Duplication、SIG-UnitSize、 SIG-UnitComplexity、SIG-ModuleCoupling、SIG-ComponentEntanglement、SIG-ComponentIndepence、Mark-CodeCoverage
  • 可重用性: SPACE-S、SIG-UnitSize
  • 可測試性: SPACE-S、SIG-Unit-Size、SIG-ModuleCoupling
  • 可靠性: SPACE-S、Mark-BugError、Mark-DevSupport、Mark-CodeCoverage

最後的結果大概就如上吧,雖然還不到完全,但至少已經有個雛形了,接下來應該就是這些指標如何取得,這個應該會開一篇來說說SonarQube

總於快完賽了…… 快往生了……


上一篇
Day-27: 如何降低 Query 複雜性的探索
下一篇
Day-29: 如何產生指標之SonarQube + 其它
系列文
一個好的系統之好維護基本篇 ( 馬克版 )30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言